package com.yfp.operation.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingV3Request;
import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingV3Result;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.ProfitSharingService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.yfp.common.core.constant.SecurityConstants;
import com.yfp.common.core.domain.R;
import com.yfp.common.security.utils.SecurityUtils;
import com.yfp.operation.config.WxPayConfiguration;
import com.yfp.operation.config.WxPayProperties;
import com.yfp.operation.domain.*;
import com.yfp.operation.domain.dto.UserWithdrawCheckDTO;
import com.yfp.operation.domain.dto.UserWithdrawRequestDTO;
import com.yfp.operation.domain.dto.UserWithdrawResponseDTO;
import com.yfp.operation.domain.dto.UserWithdrawResponseInfoDTO;
import com.yfp.operation.enums.*;
import com.yfp.operation.enums.*;
import com.yfp.operation.mapper.UserAccountMapper;
import com.yfp.operation.mapper.UserBillMapper;
import com.yfp.operation.mapper.UserWithdrawDetailMapper;
import com.yfp.operation.mapper.UserWithdrawMapper;
import com.yfp.operation.service.*;
import com.yfp.operation.service.*;
import com.yfp.operation.utils.DateUtils;
import com.yfp.system.api.RemoteUserService;
import com.yfp.system.api.domain.SysDictData;
import com.yfp.operation.domain.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description: 用户提现账单
 * 
 * @CreateDate: 2024/5/28 14:19
 * @UpdateUser: 
 * @UpdateDate: 2024/5/28 14:19
 * @UpdateRemark: 暂无修改
 * @Version: 1.0
 */
@Service
@Slf4j
public class UserWithdrawServiceImpl implements UserWithdrawService {
    @Autowired
    private UserWithdrawMapper userWithdrawMapper;
    @Autowired
    private UserWithdrawDetailMapper userWithdrawDetailMapper;
    @Autowired
    private UserBillMapper userBillMapper;
    @Autowired
    private UserAccountMapper userAccountMapper;
    @Autowired
    private AliPayService aliPayService;
    @Autowired
    private PositionSharingService positionSharingService;
    @Autowired
    private WxPayProperties wxPayProperties;
    @Autowired
    private OrderListService orderListService;
    @Autowired
    private UserBillService userBillService;
    @Autowired
    private BillProfitSharingService profitSharingService;
    @Autowired
    private OrderComboService orderComboService;
    @Autowired
    private RemoteUserService remoteUserService;


    /**
     * 新增用户提现
     *
     * @param userWithdraw
     */
    @Override
    public void add(UserWithdraw userWithdraw) {
        userWithdrawMapper.add(userWithdraw);
    }

    /**
     * 修改用户提现
     *
     * @param userWithdraw
     */
    @Override
    public void edit(UserWithdraw userWithdraw) {
        userWithdrawMapper.edit(userWithdraw);
    }

    /**
     * 查询用户提现记录
     *
     * @return
     */
    @Override
    public List<UserWithdraw> getAccountWithdraw() {
        Long userId = SecurityUtils.getUserId();
        return userWithdrawMapper.getByUserId(userId);
    }

    /**
     * 当前登录账号提现
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void accountWithdraw() {
        Long userId = SecurityUtils.getUserId();
        UserAccount userAccount = userAccountMapper.getByUserId(userId);
        List<UserBill> userBills = userBillMapper.findByUserIdAndStatus(userId, UserBillStatusEnums.CARRYTO.getStatus());
        List<Long> userBillIds = userBills.stream().map(UserBill::getId).collect(Collectors.toList());
        if (CollUtil.isEmpty(userBillIds)) {
            return;
        }
//        userBillMapper.editStatusInIds(userBillIds, UserBillStatusEnums.WITHDRAWN.getStatus());
        // 求和本次提现总额
        BigDecimal userTotalMoney = userBills.stream().map(UserBill::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);

        UserWithdraw userWithdraw = new UserWithdraw();
        userWithdraw.setUserId(userId);
        userWithdraw.setWithdrawSn(this.getWithdrawSn(userId));
        userWithdraw.setMoney(userTotalMoney);
        userWithdraw.setStatus(UserWithdrawStatusEnums.PENDING_REVIEW.getStatus());
        userWithdraw.setApplyTime(DateUtils.getDate());
        userWithdraw.setCurrentBalance(new BigDecimal("0"));
//        userWithdraw.setCurrentBalance(userAccount.getBalance().subtract(userTotalMoney));
        userWithdrawMapper.add(userWithdraw);

        // 查询点位分账账户
        List<String> positionIds = userBills.stream().map(UserBill::getPositionId).collect(Collectors.toList());
        List<PositionSharing> positionSharings = positionSharingService.getByPositionIdsAndUserId(positionIds, userId);

        Map<String, PositionSharing> positionSharingMap = positionSharings.stream().collect(Collectors.toMap(PositionSharing::getPositionId, positionSharing -> positionSharing));

        // 封装提现详情
        List<UserWithdrawDetail> details = new ArrayList<>();
        UserWithdrawDetail detail = null;
        for (UserBill userBill : userBills.stream().filter(item -> NumberUtil.isGreater(item.getMoney(), BigDecimal.ZERO)).collect(Collectors.toList())) {
            detail = new UserWithdrawDetail();
            detail.setUserWithdrawId(userWithdraw.getId());
            detail.setUserBillId(userBill.getId());
            PositionSharing positionSharing = positionSharingMap.get(userBill.getPositionId());
            detail.setAccountNumber(positionSharing.getAccountNumber());
            details.add(detail);
        }
        userWithdrawDetailMapper.adds(details);

        userAccount.setAuditWithdrawnMoney(userAccount.getAuditWithdrawnMoney().add(userTotalMoney));
        userAccount.setBalance(userAccount.getBalance().subtract(userTotalMoney));
        userAccountMapper.edit(userAccount);
    }

    /**
     * 生成当前登录账号提现编号
     *
     * @return
     */
    @Override
    public String getWithdrawSn(Long userId) {
        String maxWithdrawSn = userWithdrawMapper.getMaxWithdrawSnByUserId(userId);
        if (maxWithdrawSn == null) {
            return "1";
        }
        BigDecimal newMaxWithdrawSn = NumberUtil.add(maxWithdrawSn, "1");
        return newMaxWithdrawSn.toString();
    }

    /**
     * 获取提现管理列表
     *
     * @return
     */
    @Override
    public List<UserWithdrawResponseDTO> getManagementWithdrawList(UserWithdrawRequestDTO requestDTO) {
        return userWithdrawMapper.getManagementWithdrawList(requestDTO);
    }

    /**
     * 获取提现管理详情
     *
     * @param userWithdrawId 用户提现账单id
     * @return
     */
    @Override
    public List<UserWithdrawResponseInfoDTO> getManagementWithdrawInfo(Long userWithdrawId) {
        return userWithdrawDetailMapper.getUserWithdrawDetail(userWithdrawId);
    }

    /**
     * 提现管理审核
     *
     * @param userWithdrawCheckDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void managementWithdrawCheck(UserWithdrawCheckDTO userWithdrawCheckDTO) throws WxPayException {
        log.info("审核入参:{}", userWithdrawCheckDTO);

        // 根据提现记录id获取分账订单id
        List<Long> userBillIds = userWithdrawDetailMapper.getUserBillIdByWithdrawId(userWithdrawCheckDTO.getId());
        if (CollUtil.isEmpty(userBillIds)){
            return;
        }
        // 获取本次提现金额
        UserWithdraw withdraw = userWithdrawMapper.getById(userWithdrawCheckDTO.getId());
        BigDecimal money = withdraw.getMoney();
        // 账户信息
        UserAccount account = userAccountMapper.getByUserId(withdraw.getUserId());

        UserWithdraw userWithdraw = BeanUtil.toBean(userWithdrawCheckDTO, UserWithdraw.class);
        userWithdraw.setAuditUserId(userWithdrawCheckDTO.getAuditUserId());
        userWithdraw.setAuditTime(DateUtils.getDate());
        userWithdrawMapper.edit(userWithdraw);

        // 审核被驳回，修改分成订单的状态
        if (userWithdrawCheckDTO.getStatus().equals(UserWithdrawStatusEnums.REJECTED.getStatus())) {
            // 批量修改分成订单状态
            userBillMapper.editStatusInIds(userBillIds, UserBillStatusEnums.CARRYTO.getStatus());
            // 修改账户信息
            account.setAuditWithdrawnMoney(account.getAuditWithdrawnMoney().subtract(money));
            account.setBalance(account.getBalance().add(money));
            userAccountMapper.edit(account);
        } else if (userWithdrawCheckDTO.getStatus().equals(UserWithdrawStatusEnums.AWAITING_PAYMENT.getStatus())) {
            // 审核通过，打款
            List<UserBill> userBills = userBillService.getByIdsIn(userBillIds);
            BigDecimal billMoney = userBills.stream().map(UserBill::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
            if (!NumberUtil.equals(billMoney, money)) {
                throw new RuntimeException("本次提现金额与订单分成金额不一致，仅可驳回");
            }
            profitSharingService.profitSharing(userWithdrawCheckDTO.getId());
            // 批量修改分成订单状态
//            userBillMapper.editStatusInIds(userBillIds, UserBillStatusEnums.WITHDRAWN.getStatus());
            account.setAuditWithdrawnMoney(account.getAuditWithdrawnMoney().subtract(money));
            account.setWithdrawnMoney(account.getWithdrawnMoney().add(money));
            userAccountMapper.edit(account);
        }
    }

    @Override
    public void profitSharingByOrderSn(String orderSn) {
        WxPayService mxPayService = WxPayConfiguration.getMxPayService(wxPayProperties.getConfigs().get(1));
        List<UserBill> userBills = userBillMapper.findByOrderSn(orderSn);
        log.info("开始分账：{}", userBills);
        UserWithdrawDetail userWithdrawDetail = null;
        ProfitSharingV3Request profitSharingV3Request = null;
        for (UserBill userBill : userBills) {
            profitSharingV3Request = new ProfitSharingV3Request();
            List<ProfitSharingV3Request.Receiver> receivers = new ArrayList<>();
            ProfitSharingV3Request.Receiver receiver = new ProfitSharingV3Request.Receiver();
            receiver.setAccount(userBill.getIndependentAccount());
            // 微信分为单位
            receiver.setAmount(userBill.getMoney().multiply(BigDecimal.valueOf(100)).intValue());
            receiver.setType(userBill.getUserType() == UserTypeEnums.PERSON.getType() ? ReceiverTypeEnums.PERSONAL_OPENID.getType() : ReceiverTypeEnums.MERCHANT_ID.getType());
            UserTypeEnums userTypeEnums = UserTypeEnums.getByType(userBill.getUserType());
            receiver.setDescription("分账给-" + userTypeEnums.getName() + "-" + userBill.getNickName());
            receivers.add(receiver);
            // 查询是否还有为提现的订单
            List<UserBill> userBills1 = userBillService.getByOrderSnAndStatusNot(userBill.getOrderSn(), UserBillStatusEnums.WITHDRAWN.getStatus());
            // 查询订单支付编号
            List<OrderListDO> orderListDOS = orderListService.getByOrderSn(userBill.getOrderSn());
            OrderComboDO orderComboDO = orderComboService.getOrderComboByOrderId(orderSn);

            profitSharingV3Request.setReceivers(receivers);
            profitSharingV3Request.setAppid(wxPayProperties.getConfigs().get(1).getAppId());
            profitSharingV3Request.setOutOrderNo(userBill.getId() + "-" + userBill.getUserId());
            profitSharingV3Request.setUnfreezeUnsplit(userBills1.size() == 1 ? true : false);
            profitSharingV3Request.setTransactionId(orderListDOS.get(0).getPayTradeNo());
            profitSharingV3Request.setSubMchId(orderComboDO.getMerchantId());

            ProfitSharingService profitSharingService = mxPayService.getProfitSharingService();
            ProfitSharingV3Result profitSharingV3Result = null;

            userWithdrawDetail = new UserWithdrawDetail();
            try {
                profitSharingV3Result = profitSharingService.profitSharingV3(profitSharingV3Request);
                List<ProfitSharingV3Result.Receiver> resultReceivers = profitSharingV3Result.getReceivers();
                userWithdrawDetail.setUserBillId(userBill.getId());
                if (resultReceivers.get(0).getResult().equals("PENDING")) {
                    userWithdrawDetail.setStatus(UserWithdrawDetailStatusEnums.PENDING.getStatus());
                    log.info("分账失败，响应为：{}", profitSharingV3Result);
                } else if (resultReceivers.get(0).getResult().equals("SUCCESS")) {
                    userWithdrawDetail.setStatus(UserWithdrawDetailStatusEnums.SUCCESS.getStatus());
                } else if (resultReceivers.get(0).getResult().equals("CLOSED")) {
                    userWithdrawDetail.setStatus(UserWithdrawDetailStatusEnums.CLOSED.getStatus());
                }
                userWithdrawDetailMapper.editByBillId(userWithdrawDetail);
            } catch (Exception e) {
                e.printStackTrace();
                log.info("分账异常，profitSharingV3Result:{}", profitSharingV3Result);
            }
        }
    }

    /**
     * 服务商提现
     */
    @Override
    public void providerWithdraw() {
        // 从字典中获取服务商
        R<SysDictData> dictInfoByDictCode = remoteUserService.getDictInfoByDictCode(122L, SecurityConstants.INNER);
        if (R.isError(dictInfoByDictCode)) {
            log.error("从字典中获取服务商异常:{}", dictInfoByDictCode.getMsg());
            return;
        }
        SysDictData sysDictData = dictInfoByDictCode.getData();
        Long userId = Long.valueOf(sysDictData.getDictValue());

        UserAccount userAccount = userAccountMapper.getByUserId(userId);

        // 判断账户余额是否大于1000
        if (null == userAccount || null == userAccount.getBalance() || NumberUtil.isLess(userAccount.getBalance(), BigDecimal.valueOf(1000))) {
            return;
        }

        List<UserBill> userBills = userBillMapper.findByUserIdAndStatus(userId, UserBillStatusEnums.CARRYTO.getStatus());
        List<Long> userBillIds = userBills.stream().map(UserBill::getId).collect(Collectors.toList());
        if (CollUtil.isEmpty(userBillIds)) {
            return;
        }
        userBillMapper.editStatusInIds(userBillIds, UserBillStatusEnums.WITHDRAWN.getStatus());
        // 求和本次提现总额
        BigDecimal userTotalMoney = userBills.stream().map(UserBill::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);

        UserWithdraw userWithdraw = new UserWithdraw();
        userWithdraw.setUserId(userId);
        userWithdraw.setWithdrawSn(this.getWithdrawSn(userId));
        userWithdraw.setMoney(userTotalMoney);
        userWithdraw.setStatus(UserWithdrawStatusEnums.PENDING_REVIEW.getStatus());
        userWithdraw.setApplyTime(DateUtils.getDate());
        userWithdraw.setCurrentBalance(userAccount.getBalance().subtract(userTotalMoney));
        userWithdrawMapper.add(userWithdraw);

        // 查询点位分账账户
        List<String> positionIds = userBills.stream().map(UserBill::getPositionId).collect(Collectors.toList());
        List<PositionSharing> positionSharings = positionSharingService.getByPositionIdsAndUserId(positionIds, userId);

        Map<String, PositionSharing> positionSharingMap = positionSharings.stream().collect(Collectors.toMap(PositionSharing::getPositionId, positionSharing -> positionSharing));

        // 封装提现详情
        List<UserWithdrawDetail> details = new ArrayList<>();
        UserWithdrawDetail detail = null;
        for (UserBill userBill : userBills) {
            detail = new UserWithdrawDetail();
            detail.setUserWithdrawId(userWithdraw.getId());
            detail.setUserBillId(userBill.getId());
            PositionSharing positionSharing = positionSharingMap.get(userBill.getPositionId());
            detail.setAccountNumber(positionSharing.getAccountNumber());
            details.add(detail);
        }
        userWithdrawDetailMapper.adds(details);

        userAccount.setAuditWithdrawnMoney(userAccount.getAuditWithdrawnMoney().add(userTotalMoney));
        userAccountMapper.edit(userAccount);
    }
}